"""
Adapter Manager - centralized management of all data adapters.

This module provides the AdapterManager class that handles:
- Adapter initialization and lifecycle management
- Adapter registration and discovery
- Connection pooling and resource management
- Health monitoring and reconnection logic
- Configuration parsing from service_config.py

Example:
    Basic usage:
    
    >>> from app.adapters.manager import AdapterManager
    >>> from app.config import service_config
    >>> 
    >>> manager = AdapterManager(config=service_config)
    >>> await manager.initialize()
    >>> 
    >>> # Get a specific adapter
    >>> tushare = manager.get_adapter('tushare')
    >>> bars = await tushare.query_bars('000001.SZ', start_date='2024-01-01')
    >>> 
    >>> await manager.cleanup()

Configuration Format:
    The manager expects configuration in service_config.py:
    
    ADAPTERS_CONFIG = {
        'tushare': {
            'enabled': True,
            'class': 'app.adapters.providers.tushare_adapter.TushareAdapter',
            'config': {
                'token': 'your_token_here',
                'timeout': 30,
            }
        },
        'ctp': {
            'enabled': True,
            'class': 'app.adapters.providers.ctp_futures_adapter.CTPFuturesAdapter',
            'config': {
                'broker_id': 'xxxx',
                'user_id': 'xxxx',
            }
        }
    }
"""

import asyncio
import importlib
import logging
from typing import Dict, Optional, Any, List, Type
from contextlib import asynccontextmanager
from enum import Enum
from datetime import datetime, timedelta

from .core.base import DataAdapter, HistoricalDataAdapter, RealtimeDataAdapter
from .core.exceptions import (
    AdapterError,
    AdapterConfigError,
    AdapterConnectionError,
    is_retryable_error,
    get_retry_delay,
)

logger = logging.getLogger(__name__)


class AdapterState(Enum):
    """适配器状态枚举"""
    INITIALIZING = "initializing"  # 正在初始化
    RUNNING = "running"             # 运行中
    UNHEALTHY = "unhealthy"         # 不健康（运行中but健康检查失败）
    FAILED = "failed"               # 初始化失败或永久失败
    STOPPED = "stopped"             # 已停止
    DISABLED = "disabled"           # 配置中禁用


class AdapterMetadata:
    """适配器元数据"""
    def __init__(self, name: str):
        self.name = name
        self.state = AdapterState.INITIALIZING
        self.reconnect_attempts = 0
        self.last_health_check: Optional[datetime] = None
        self.last_successful_connection: Optional[datetime] = None
        self.last_error: Optional[str] = None
        self.cooldown_until: Optional[datetime] = None  # 冷却期结束时间


class AdapterManager:
    """
    Centralized manager for all data adapters.
    
    Responsibilities:
    - Parse adapter configurations from service_config
    - Dynamically load and instantiate adapter classes
    - Manage adapter lifecycle (initialize, cleanup, reconnect)
    - Provide unified access to all adapters
    - Monitor adapter health and handle failures
    
    Attributes:
        adapters: Dictionary of initialized adapters {name: adapter_instance}
        config: Service configuration object
        _health_check_task: Background task for health monitoring
        _reconnect_attempts: Track reconnection attempts per adapter
    """
    
    def __init__(self, config: Any):
        """
        Initialize the adapter manager.
        
        Args:
            config: Service configuration object (usually from service_config.py)
        """
        self.config = config
        self.adapters: Dict[str, DataAdapter] = {}
        self.adapter_metadata: Dict[str, AdapterMetadata] = {}  # 新增：适配器元数据
        self._health_check_task: Optional[asyncio.Task] = None
        self._reconnect_attempts: Dict[str, int] = {}  # 保留以兼容旧代码
        self._max_reconnect_attempts = 3
        self._health_check_interval = 60  # seconds
        self._cooldown_period = 300  # 重连冷却期：5分钟
        self._shutdown_event = asyncio.Event()
        
    async def initialize(self) -> None:
        """
        Initialize all enabled adapters from configuration.
        
        This method:
        1. Parses adapter configuration
        2. Dynamically loads adapter classes
        3. Instantiates adapters with their configs
        4. Calls initialize() on each adapter
        5. Starts background health monitoring
        
        Raises:
            AdapterConfigError: If configuration is invalid
            AdapterError: If adapter initialization fails
        """
        logger.info("Initializing adapter manager...")
        
        # Parse configuration
        adapters_config = self._parse_config()
        
        # Initialize each enabled adapter
        for name, adapter_config in adapters_config.items():
            # 创建元数据
            metadata = AdapterMetadata(name)
            self.adapter_metadata[name] = metadata
            
            if not adapter_config.get('enabled', True):
                logger.info(f"Adapter '{name}' is disabled, skipping...")
                metadata.state = AdapterState.DISABLED
                continue
                
            try:
                metadata.state = AdapterState.INITIALIZING
                
                # Load adapter class dynamically
                adapter_class = self._load_adapter_class(adapter_config['class'])
                
                # Instantiate adapter
                # 某些适配器需要配置对象而不是字典，使用 from_dict 方法
                config_data = adapter_config.get('config', {})
                
                # 检查适配器类是否有配置类和 from_dict 方法
                if hasattr(adapter_class, '__init__'):
                    import inspect
                    sig = inspect.signature(adapter_class.__init__)
                    if 'config' in sig.parameters:
                        param_type = sig.parameters['config'].annotation
                        # 如果配置参数有类型注解且有 from_dict 方法，使用它
                        if param_type != inspect.Parameter.empty and hasattr(param_type, 'from_dict'):
                            config_data = param_type.from_dict(config_data)
                
                adapter_instance = adapter_class(config=config_data)
                
                # Initialize adapter (if method exists)
                if hasattr(adapter_instance, 'initialize'):
                    await adapter_instance.initialize()
                
                # Store adapter
                self.adapters[name] = adapter_instance
                self._reconnect_attempts[name] = 0
                
                # 更新元数据状态为运行中
                metadata.state = AdapterState.RUNNING
                metadata.last_successful_connection = datetime.utcnow()
                
                logger.info(f"✅ Successfully initialized adapter '{name}'")
                
            except Exception as e:
                # 初始化失败，标记为永久失败状态
                metadata.state = AdapterState.FAILED
                metadata.last_error = str(e)
                logger.error(
                    f"❌ Failed to initialize adapter '{name}': {e}. "
                    f"This adapter will NOT be included in health checks.",
                    exc_info=True
                )
                # 不进行 continue，允许其他适配器初始化
        
        if not self.adapters:
            logger.warning("No adapters were successfully initialized!")
        
        # Start health monitoring
        self._health_check_task = asyncio.create_task(self._health_check_loop())
        
        logger.info(f"Adapter manager initialized with {len(self.adapters)} adapters")
    
    async def cleanup(self) -> None:
        """
        Cleanup all adapters and stop background tasks.
        
        This method:
        1. Signals shutdown to background tasks
        2. Calls cleanup() on each adapter
        3. Clears adapter registry
        """
        logger.info("Cleaning up adapter manager...")
        
        # Signal shutdown
        self._shutdown_event.set()
        
        # Cancel health check task
        if self._health_check_task:
            self._health_check_task.cancel()
            try:
                await self._health_check_task
            except asyncio.CancelledError:
                pass
        
        # Cleanup all adapters
        for name, adapter in self.adapters.items():
            try:
                await adapter.cleanup()
                logger.info(f"Cleaned up adapter '{name}'")
            except Exception as e:
                logger.error(f"Error cleaning up adapter '{name}': {e}", exc_info=True)
        
        self.adapters.clear()
        logger.info("Adapter manager cleanup complete")
    
    def get_adapter(self, name: str) -> Optional[DataAdapter]:
        """
        Get an adapter by name.
        
        Args:
            name: Adapter name (e.g., 'tushare', 'ctp')
            
        Returns:
            Adapter instance or None if not found
        """
        return self.adapters.get(name)
    
    def get_historical_adapters(self) -> List[HistoricalDataAdapter]:
        """
        Get all adapters that support historical data queries.
        
        Returns:
            List of HistoricalDataAdapter instances
        """
        return [
            adapter for adapter in self.adapters.values()
            if isinstance(adapter, HistoricalDataAdapter)
        ]
    
    def get_realtime_adapters(self) -> List[RealtimeDataAdapter]:
        """
        Get all adapters that support realtime data streaming.
        
        Returns:
            List of RealtimeDataAdapter instances
        """
        return [
            adapter for adapter in self.adapters.values()
            if isinstance(adapter, RealtimeDataAdapter)
        ]
    
    def list_adapters(self) -> List[str]:
        """
        List all initialized adapter names.
        
        Returns:
            List of adapter names
        """
        return list(self.adapters.keys())
    
    @asynccontextmanager
    async def adapter_context(self, name: str):
        """
        Context manager for safely using an adapter with automatic error handling.
        
        Args:
            name: Adapter name
            
        Yields:
            Adapter instance
            
        Example:
            >>> async with manager.adapter_context('tushare') as tushare:
            ...     bars = await tushare.query_bars('000001.SZ')
        """
        adapter = self.get_adapter(name)
        if not adapter:
            raise AdapterConfigError(f"Adapter '{name}' not found")
        
        try:
            yield adapter
        except Exception as e:
            logger.error(f"Error using adapter '{name}': {e}", exc_info=True)
            
            # Attempt reconnection if it's a retryable error
            if is_retryable_error(e):
                await self._attempt_reconnect(name, adapter)
            
            raise
    
    async def health_check(self) -> Dict[str, bool]:
        """
        Check health status of all adapters.
        
        Returns:
            Dictionary mapping adapter names to health status (True=healthy)
        """
        health_status = {}
        
        for name, adapter in self.adapters.items():
            try:
                is_healthy = await adapter.health_check()
                health_status[name] = is_healthy
            except Exception as e:
                logger.error(f"Health check failed for adapter '{name}': {e}")
                health_status[name] = False
        
        return health_status
    
    def _parse_config(self) -> Dict[str, Dict[str, Any]]:
        """
        Parse adapter configuration from service_config.
        
        Returns:
            Dictionary of adapter configurations
            
        Raises:
            AdapterConfigError: If configuration is invalid or missing
        """
        try:
            # Try to get ADAPTERS_CONFIG from config
            if hasattr(self.config, 'ADAPTERS_CONFIG'):
                return self.config.ADAPTERS_CONFIG
            
            # Fallback: try to get from dict
            if isinstance(self.config, dict) and 'ADAPTERS_CONFIG' in self.config:
                return self.config['ADAPTERS_CONFIG']
            
            # If no adapter config found, return empty dict
            logger.warning("No ADAPTERS_CONFIG found in configuration, using empty config")
            return {}
            
        except Exception as e:
            raise AdapterConfigError(f"Failed to parse adapter configuration: {e}")
    
    def _load_adapter_class(self, class_path: str) -> Type[DataAdapter]:
        """
        Dynamically load an adapter class from a module path.
        
        Args:
            class_path: Full path to class (e.g., 'app.adapters.providers.tushare_adapter.TushareAdapter')
            
        Returns:
            Adapter class
            
        Raises:
            AdapterConfigError: If class cannot be loaded
        """
        try:
            # Split module path and class name
            module_path, class_name = class_path.rsplit('.', 1)
            
            # Import module
            module = importlib.import_module(module_path)
            
            # Get class
            adapter_class = getattr(module, class_name)
            
            # Verify it's a DataAdapter
            if not issubclass(adapter_class, DataAdapter):
                raise AdapterConfigError(
                    f"Class {class_path} is not a subclass of DataAdapter"
                )
            
            return adapter_class
            
        except Exception as e:
            raise AdapterConfigError(f"Failed to load adapter class '{class_path}': {e}")
    
    async def _health_check_loop(self) -> None:
        """
        Background task that periodically checks adapter health and reconnects if needed.
        """
        logger.info("Starting adapter health check loop...")
        
        while not self._shutdown_event.is_set():
            try:
                # Wait for the check interval or shutdown signal
                await asyncio.wait_for(
                    self._shutdown_event.wait(),
                    timeout=self._health_check_interval
                )
                # If we get here, shutdown was signaled
                break
                
            except asyncio.TimeoutError:
                # Timeout means it's time for a health check
                pass
            
            # Perform health checks (只检查运行中或不健康的适配器，跳过失败和禁用的)
            health_status = await self.health_check()
            
            # Handle unhealthy adapters
            for name, is_healthy in health_status.items():
                metadata = self.adapter_metadata.get(name)
                
                if not metadata:
                    continue
                
                # 只对运行中、不健康状态的适配器进行重连
                # 跳过：FAILED（初始化失败）、DISABLED（配置禁用）状态的适配器
                if metadata.state in [AdapterState.FAILED, AdapterState.DISABLED]:
                    continue
                
                if not is_healthy:
                    logger.warning(f"⚠️ Adapter '{name}' is unhealthy, attempting reconnection...")
                    metadata.state = AdapterState.UNHEALTHY
                    adapter = self.adapters.get(name)
                    if adapter:
                        await self._attempt_reconnect(name, adapter)
                else:
                    # 健康检查成功，确保状态为RUNNING
                    if metadata.state == AdapterState.UNHEALTHY:
                        metadata.state = AdapterState.RUNNING
                        logger.info(f"✅ Adapter '{name}' recovered to healthy state")
                    
                    metadata.last_health_check = datetime.utcnow()
        
        logger.info("Health check loop stopped")
    
    async def _attempt_reconnect(self, name: str, adapter: DataAdapter) -> None:
        """
        改进版重连逻辑：支持冷却期和更智能的状态管理
        
        Args:
            name: Adapter name
            adapter: Adapter instance
        """
        metadata = self.adapter_metadata.get(name)
        if not metadata:
            logger.error(f"Adapter '{name}' metadata not found")
            return
        
        # 检查是否在冷却期内
        if metadata.cooldown_until and datetime.utcnow() < metadata.cooldown_until:
            remaining = (metadata.cooldown_until - datetime.utcnow()).total_seconds()
            logger.debug(
                f"Adapter '{name}' is in cooldown period, "
                f"skipping reconnection (remaining: {remaining:.0f}s)"
            )
            return
        
        attempts = metadata.reconnect_attempts
        
        if attempts >= self._max_reconnect_attempts:
            # 进入冷却期
            metadata.cooldown_until = datetime.utcnow() + timedelta(seconds=self._cooldown_period)
            metadata.reconnect_attempts = 0  # 重置计数器，准备冷却期后重试
            logger.warning(
                f"⚠️ Adapter '{name}' exceeded max reconnect attempts ({self._max_reconnect_attempts}), "
                f"entering cooldown period ({self._cooldown_period}s)"
            )
            return
        
        try:
            logger.info(f"🔄 Attempting to reconnect adapter '{name}' (attempt {attempts + 1})...")
            
            # Cleanup first
            await adapter.cleanup()
            
            # Wait with exponential backoff
            delay = get_retry_delay(attempts)
            logger.info(f"Waiting {delay}s before reconnecting adapter '{name}'...")
            await asyncio.sleep(delay)
            
            # Reinitialize
            await adapter.initialize()
            
            # 重连成功！重置所有计数器和状态
            metadata.reconnect_attempts = 0
            metadata.cooldown_until = None
            metadata.state = AdapterState.RUNNING
            metadata.last_successful_connection = datetime.utcnow()
            metadata.last_error = None
            self._reconnect_attempts[name] = 0  # 兼容旧代码
            
            logger.info(f"✅ Successfully reconnected adapter '{name}'")
            
        except Exception as e:
            # 重连失败
            metadata.reconnect_attempts = attempts + 1
            metadata.last_error = str(e)
            metadata.state = AdapterState.UNHEALTHY
            self._reconnect_attempts[name] = attempts + 1  # 兼容旧代码
            
            logger.error(
                f"❌ Failed to reconnect adapter '{name}' "
                f"(attempt {attempts + 1}/{self._max_reconnect_attempts}): {e}",
                exc_info=True
            )
    
    async def reload_adapter(self, name: str) -> bool:
        """
        Reload a specific adapter (cleanup and reinitialize).
        
        Args:
            name: Adapter name
            
        Returns:
            True if successful, False otherwise
        """
        adapter = self.adapters.get(name)
        if not adapter:
            logger.error(f"Adapter '{name}' not found")
            return False
        
        try:
            logger.info(f"Reloading adapter '{name}'...")
            await adapter.cleanup()
            await adapter.initialize()
            self._reconnect_attempts[name] = 0
            logger.info(f"Successfully reloaded adapter '{name}'")
            return True
            
        except Exception as e:
            logger.error(f"Failed to reload adapter '{name}': {e}", exc_info=True)
            return False
    
    def get_adapter_info(self) -> Dict[str, Dict[str, Any]]:
        """
        Get comprehensive information about all adapters including state and metadata.
        
        Returns:
            Dictionary with adapter info including type, status, state, etc.
        """
        info = {}
        
        # 包含所有已配置的适配器（包括失败和禁用的）
        for name, metadata in self.adapter_metadata.items():
            adapter = self.adapters.get(name)
            
            adapter_info = {
                'state': metadata.state.value,
                'reconnect_attempts': metadata.reconnect_attempts,
                'last_health_check': metadata.last_health_check.isoformat() if metadata.last_health_check else None,
                'last_successful_connection': metadata.last_successful_connection.isoformat() if metadata.last_successful_connection else None,
                'last_error': metadata.last_error,
                'in_cooldown': metadata.cooldown_until and datetime.utcnow() < metadata.cooldown_until,
                'cooldown_remaining_seconds': (
                    (metadata.cooldown_until - datetime.utcnow()).total_seconds()
                    if metadata.cooldown_until and datetime.utcnow() < metadata.cooldown_until
                    else None
                ),
            }
            
            # 如果适配器实例存在，添加类型信息
            if adapter:
                adapter_info.update({
                    'class': adapter.__class__.__name__,
                    'module': adapter.__class__.__module__,
                    'is_historical': isinstance(adapter, HistoricalDataAdapter),
                    'is_realtime': isinstance(adapter, RealtimeDataAdapter),
                })
            
            info[name] = adapter_info
        
        return info


# Singleton instance for global access (optional pattern)
_manager_instance: Optional[AdapterManager] = None


def get_manager() -> Optional[AdapterManager]:
    """
    Get the global adapter manager instance.
    
    Returns:
        AdapterManager instance or None if not initialized
    """
    return _manager_instance


def set_manager(manager: AdapterManager) -> None:
    """
    Set the global adapter manager instance.
    
    Args:
        manager: AdapterManager instance
    """
    global _manager_instance
    _manager_instance = manager

